#include <bits/stdc++.h>
using namespace std;
int n;
int u, v, w;
int mp[50][50];
int ans[50];
int vis[50];
queue<int> qp;
queue<int> qs;
void BFS()
{
	//基本思路
	//由于边权只有0或1,所以可以手动分情况讨论
	//我们知道,在广搜中,某点的最短路是"自起点开始广搜最早到达此点的距离"
	//但是以上说法是在边权为1时成立
	//当边权为0或1时,以上说法不再成立,因为边权为0的边连接的点不一定先被
	//入队
	//于是考虑先将边权为0的点入队,再将边权为1的点入队,以保证解最优
	while (!qp.empty() && !qs.empty())
	{
		int tp = qp.front();
		int ts = qs.front();
		ans[tp] = ts;
		for (int i = 1; i <= n; i++)
		{
			if (mp[tp][i] == 0 && tp != i && vis[i] == 0)
			{
				vis[i] = 1;
				//此处vis的作用:我们默认首次到达此点的距离最短,此后
				//到达此点的路径无论距离远近都忽视掉
				//事实上,这一规律是由广搜的性质决定的
				qp.push(i);
				qs.push(ts);
			}
		}
		for (int i = 1; i <= n; i++)
		{
			if (mp[tp][i] == 1 && tp != i && vis[i] == 0)
			{
				vis[i] = 1;
				qp.push(i);
				qs.push(ts + 1);
			}
		}
		qp.pop();
		qs.pop();
	}
}
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			if (i == j)
				mp[i][j] = 0;
			else
				mp[i][j] = 99999;
	for (int i = 1; i <= n; i++)
	{
		cin >> u >> v >> w;
		mp[u][v] = w;
	}
	qp.push(1);
	qs.push(0);
	memset(ans, 1, sizeof(ans));
	BFS();
	for (int i = 1; i <= n; i++)
		cout << ans[i] << ' ';
	return 0;
}